mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Rename Fill to Paint
This commit is contained in:
parent
7e2c217cbc
commit
fd0b89a1d8
@ -4,7 +4,7 @@ use std::rc::Rc;
|
|||||||
use crate::color::{Color, RgbaColor};
|
use crate::color::{Color, RgbaColor};
|
||||||
use crate::font::{FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric};
|
use crate::font::{FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric};
|
||||||
use crate::geom::*;
|
use crate::geom::*;
|
||||||
use crate::layout::Fill;
|
use crate::layout::Paint;
|
||||||
use crate::paper::{Paper, PaperClass, PAPER_A4};
|
use crate::paper::{Paper, PaperClass, PAPER_A4};
|
||||||
|
|
||||||
/// The execution state.
|
/// The execution state.
|
||||||
@ -117,8 +117,8 @@ pub struct FontState {
|
|||||||
pub top_edge: VerticalFontMetric,
|
pub top_edge: VerticalFontMetric,
|
||||||
/// The bottom end of the text bounding box.
|
/// The bottom end of the text bounding box.
|
||||||
pub bottom_edge: VerticalFontMetric,
|
pub bottom_edge: VerticalFontMetric,
|
||||||
/// The glyph fill color / texture.
|
/// Glyph color.
|
||||||
pub fill: Fill,
|
pub fill: Paint,
|
||||||
/// Whether the strong toggle is active or inactive. This determines
|
/// Whether the strong toggle is active or inactive. This determines
|
||||||
/// whether the next `*` adds or removes font weight.
|
/// whether the next `*` adds or removes font weight.
|
||||||
pub strong: bool,
|
pub strong: bool,
|
||||||
@ -152,7 +152,7 @@ impl Default for FontState {
|
|||||||
size: Length::pt(11.0),
|
size: Length::pt(11.0),
|
||||||
top_edge: VerticalFontMetric::CapHeight,
|
top_edge: VerticalFontMetric::CapHeight,
|
||||||
bottom_edge: VerticalFontMetric::Baseline,
|
bottom_edge: VerticalFontMetric::Baseline,
|
||||||
fill: Fill::Color(Color::Rgba(RgbaColor::BLACK)),
|
fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)),
|
||||||
strong: false,
|
strong: false,
|
||||||
emph: false,
|
emph: false,
|
||||||
strikethrough: None,
|
strikethrough: None,
|
||||||
@ -165,8 +165,10 @@ impl Default for FontState {
|
|||||||
/// Describes a line that could be positioned over, under or on top of text.
|
/// Describes a line that could be positioned over, under or on top of text.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
||||||
pub struct LineState {
|
pub struct LineState {
|
||||||
/// Stroke color of the line. Defaults to the text color if `None`.
|
/// Stroke color of the line.
|
||||||
pub stroke: Option<Fill>,
|
///
|
||||||
|
/// Defaults to the text color if `None`.
|
||||||
|
pub stroke: Option<Paint>,
|
||||||
/// Thickness of the line's stroke. Calling functions should attempt to
|
/// Thickness of the line's stroke. Calling functions should attempt to
|
||||||
/// read this value from the appropriate font tables if this is `None`.
|
/// read this value from the appropriate font tables if this is `None`.
|
||||||
pub thickness: Option<Linear>,
|
pub thickness: Option<Linear>,
|
||||||
|
@ -18,7 +18,7 @@ use crate::color::Color;
|
|||||||
use crate::font::{Em, FaceId};
|
use crate::font::{Em, FaceId};
|
||||||
use crate::geom::{self, Length, Size};
|
use crate::geom::{self, Length, Size};
|
||||||
use crate::image::{Image, ImageId};
|
use crate::image::{Image, ImageId};
|
||||||
use crate::layout::{Element, Fill, Frame, Shape};
|
use crate::layout::{Element, Frame, Geometry, Paint};
|
||||||
|
|
||||||
/// Export a collection of frames into a PDF document.
|
/// Export a collection of frames into a PDF document.
|
||||||
///
|
///
|
||||||
@ -142,7 +142,7 @@ impl<'a> PdfExporter<'a> {
|
|||||||
// do that, we need to remember the active face.
|
// do that, we need to remember the active face.
|
||||||
let mut face = None;
|
let mut face = None;
|
||||||
let mut size = Length::zero();
|
let mut size = Length::zero();
|
||||||
let mut fill: Option<Fill> = None;
|
let mut fill: Option<Paint> = None;
|
||||||
|
|
||||||
for (pos, element) in page.elements() {
|
for (pos, element) in page.elements() {
|
||||||
let x = pos.x.to_pt() as f32;
|
let x = pos.x.to_pt() as f32;
|
||||||
@ -172,30 +172,32 @@ impl<'a> PdfExporter<'a> {
|
|||||||
text.show(Str(&shaped.encode_glyphs_be()));
|
text.show(Str(&shaped.encode_glyphs_be()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Element::Geometry(ref shape, fill) => {
|
Element::Geometry(ref geometry, paint) => {
|
||||||
content.save_state();
|
content.save_state();
|
||||||
write_fill(&mut content, fill);
|
|
||||||
|
|
||||||
match *shape {
|
match *geometry {
|
||||||
Shape::Rect(Size { width, height }) => {
|
Geometry::Rect(Size { width, height }) => {
|
||||||
let w = width.to_pt() as f32;
|
let w = width.to_pt() as f32;
|
||||||
let h = height.to_pt() as f32;
|
let h = height.to_pt() as f32;
|
||||||
if w > 0.0 && h > 0.0 {
|
if w > 0.0 && h > 0.0 {
|
||||||
|
write_fill(&mut content, paint);
|
||||||
content.rect(x, y - h, w, h, false, true);
|
content.rect(x, y - h, w, h, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Shape::Ellipse(size) => {
|
Geometry::Ellipse(size) => {
|
||||||
let path = geom::Path::ellipse(size);
|
let path = geom::Path::ellipse(size);
|
||||||
|
write_fill(&mut content, paint);
|
||||||
write_path(&mut content, x, y, &path, false, true);
|
write_path(&mut content, x, y, &path, false, true);
|
||||||
}
|
}
|
||||||
Shape::Line(target, stroke) => {
|
Geometry::Line(target, thickness) => {
|
||||||
write_stroke(&mut content, fill, stroke.to_pt() as f32);
|
write_stroke(&mut content, paint, thickness.to_pt() as f32);
|
||||||
content.path(true, false).move_to(x, y).line_to(
|
content.path(true, false).move_to(x, y).line_to(
|
||||||
x + target.x.to_pt() as f32,
|
x + target.x.to_pt() as f32,
|
||||||
y - target.y.to_pt() as f32,
|
y - target.y.to_pt() as f32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Shape::Path(ref path) => {
|
Geometry::Path(ref path) => {
|
||||||
|
write_fill(&mut content, paint);
|
||||||
write_path(&mut content, x, y, path, false, true)
|
write_path(&mut content, x, y, path, false, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,18 +371,15 @@ impl<'a> PdfExporter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write a fill change into a content stream.
|
/// Write a fill change into a content stream.
|
||||||
fn write_fill(content: &mut Content, fill: Fill) {
|
fn write_fill(content: &mut Content, fill: Paint) {
|
||||||
match fill {
|
let Paint::Color(Color::Rgba(c)) = fill;
|
||||||
Fill::Color(Color::Rgba(c)) => {
|
|
||||||
content.fill_rgb(c.r as f32 / 255.0, c.g as f32 / 255.0, c.b as f32 / 255.0);
|
content.fill_rgb(c.r as f32 / 255.0, c.g as f32 / 255.0, c.b as f32 / 255.0);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a stroke change into a content stream.
|
/// Write a stroke change into a content stream.
|
||||||
fn write_stroke(content: &mut Content, fill: Fill, thickness: f32) {
|
fn write_stroke(content: &mut Content, stroke: Paint, thickness: f32) {
|
||||||
match fill {
|
match stroke {
|
||||||
Fill::Color(Color::Rgba(c)) => {
|
Paint::Color(Color::Rgba(c)) => {
|
||||||
content.stroke_rgb(
|
content.stroke_rgb(
|
||||||
c.r as f32 / 255.0,
|
c.r as f32 / 255.0,
|
||||||
c.g as f32 / 255.0,
|
c.g as f32 / 255.0,
|
||||||
|
@ -6,8 +6,8 @@ use super::*;
|
|||||||
pub struct BackgroundNode {
|
pub struct BackgroundNode {
|
||||||
/// The kind of shape to use as a background.
|
/// The kind of shape to use as a background.
|
||||||
pub shape: BackgroundShape,
|
pub shape: BackgroundShape,
|
||||||
/// The background fill.
|
/// Background color / texture.
|
||||||
pub fill: Fill,
|
pub fill: Paint,
|
||||||
/// The child node to be filled.
|
/// The child node to be filled.
|
||||||
pub child: AnyNode,
|
pub child: AnyNode,
|
||||||
}
|
}
|
||||||
@ -29,19 +29,16 @@ impl Layout for BackgroundNode {
|
|||||||
for frame in &mut frames {
|
for frame in &mut frames {
|
||||||
let mut new = Frame::new(frame.size, frame.baseline);
|
let mut new = Frame::new(frame.size, frame.baseline);
|
||||||
|
|
||||||
let (point, shape) = match self.shape {
|
let (point, geometry) = match self.shape {
|
||||||
BackgroundShape::Rect => (Point::zero(), Shape::Rect(frame.size)),
|
BackgroundShape::Rect => (Point::zero(), Geometry::Rect(frame.size)),
|
||||||
BackgroundShape::Ellipse => {
|
BackgroundShape::Ellipse => {
|
||||||
(frame.size.to_point() / 2.0, Shape::Ellipse(frame.size))
|
(frame.size.to_point() / 2.0, Geometry::Ellipse(frame.size))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let element = Element::Geometry(shape, self.fill);
|
|
||||||
new.push(point, element);
|
|
||||||
|
|
||||||
let prev = std::mem::take(&mut frame.item);
|
let prev = std::mem::take(&mut frame.item);
|
||||||
|
new.push(point, Element::Geometry(geometry, self.fill));
|
||||||
new.push_frame(Point::zero(), prev);
|
new.push_frame(Point::zero(), prev);
|
||||||
|
|
||||||
*Rc::make_mut(&mut frame.item) = new;
|
*Rc::make_mut(&mut frame.item) = new;
|
||||||
}
|
}
|
||||||
frames
|
frames
|
||||||
|
@ -110,8 +110,9 @@ enum Child {
|
|||||||
pub enum Element {
|
pub enum Element {
|
||||||
/// Shaped text.
|
/// Shaped text.
|
||||||
Text(Text),
|
Text(Text),
|
||||||
/// A filled geometric shape.
|
/// A geometric shape and the paint which with it should be filled or
|
||||||
Geometry(Shape, Fill),
|
/// stroked.
|
||||||
|
Geometry(Geometry, Paint),
|
||||||
/// A raster image.
|
/// A raster image.
|
||||||
Image(ImageId, Size),
|
Image(ImageId, Size),
|
||||||
}
|
}
|
||||||
@ -123,8 +124,8 @@ pub struct Text {
|
|||||||
pub face_id: FaceId,
|
pub face_id: FaceId,
|
||||||
/// The font size.
|
/// The font size.
|
||||||
pub size: Length,
|
pub size: Length,
|
||||||
/// The glyph's fill color.
|
/// Glyph color.
|
||||||
pub fill: Fill,
|
pub fill: Paint,
|
||||||
/// The glyphs.
|
/// The glyphs.
|
||||||
pub glyphs: Vec<Glyph>,
|
pub glyphs: Vec<Glyph>,
|
||||||
}
|
}
|
||||||
@ -155,20 +156,20 @@ impl Text {
|
|||||||
|
|
||||||
/// A geometric shape.
|
/// A geometric shape.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Shape {
|
pub enum Geometry {
|
||||||
/// A rectangle with its origin in the topleft corner.
|
/// A filled rectangle with its origin in the topleft corner.
|
||||||
Rect(Size),
|
Rect(Size),
|
||||||
/// An ellipse with its origin in the center.
|
/// A filled ellipse with its origin in the center.
|
||||||
Ellipse(Size),
|
Ellipse(Size),
|
||||||
/// A line to a `Point` (relative to its position) with a stroke width.
|
/// A stroked line to a point (relative to its position) with a thickness.
|
||||||
Line(Point, Length),
|
Line(Point, Length),
|
||||||
/// A bezier path.
|
/// A filled bezier path.
|
||||||
Path(Path),
|
Path(Path),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How text and shapes are filled.
|
/// How a fill or stroke should be painted.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub enum Fill {
|
pub enum Paint {
|
||||||
/// A solid color.
|
/// A solid color.
|
||||||
Color(Color),
|
Color(Color),
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use super::{Element, Frame, Glyph, LayoutContext, Text};
|
|||||||
use crate::exec::{FontState, LineState};
|
use crate::exec::{FontState, LineState};
|
||||||
use crate::font::{Face, FaceId, FontStyle, LineMetrics};
|
use crate::font::{Face, FaceId, FontStyle, LineMetrics};
|
||||||
use crate::geom::{Dir, Length, Point, Size};
|
use crate::geom::{Dir, Length, Point, Size};
|
||||||
use crate::layout::Shape;
|
use crate::layout::Geometry;
|
||||||
use crate::util::SliceExt;
|
use crate::util::SliceExt;
|
||||||
|
|
||||||
/// The result of shaping text.
|
/// The result of shaping text.
|
||||||
@ -412,9 +412,7 @@ fn decorate(
|
|||||||
|
|
||||||
let pos = Point::new(pos.x - extent, pos.y + offset);
|
let pos = Point::new(pos.x - extent, pos.y + offset);
|
||||||
let target = Point::new(width + 2.0 * extent, Length::zero());
|
let target = Point::new(width + 2.0 * extent, Length::zero());
|
||||||
let shape = Shape::Line(target, thickness);
|
let element = Element::Geometry(Geometry::Line(target, thickness), stroke);
|
||||||
let element = Element::Geometry(shape, stroke);
|
|
||||||
|
|
||||||
frame.push(pos, element);
|
frame.push(pos, element);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,9 +3,8 @@ use std::f64::consts::SQRT_2;
|
|||||||
use decorum::N64;
|
use decorum::N64;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::color::Color;
|
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
BackgroundNode, BackgroundShape, Fill, FixedNode, ImageNode, PadNode,
|
BackgroundNode, BackgroundShape, FixedNode, ImageNode, PadNode, Paint,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// `image`: An image.
|
/// `image`: An image.
|
||||||
@ -64,10 +63,10 @@ fn rect_impl(
|
|||||||
|
|
||||||
let fixed = FixedNode { width, height, child: stack.into() };
|
let fixed = FixedNode { width, height, child: stack.into() };
|
||||||
|
|
||||||
if let Some(color) = fill {
|
if let Some(fill) = fill {
|
||||||
ctx.push_into_par(BackgroundNode {
|
ctx.push_into_par(BackgroundNode {
|
||||||
shape: BackgroundShape::Rect,
|
shape: BackgroundShape::Rect,
|
||||||
fill: Fill::Color(color),
|
fill: Paint::Color(fill),
|
||||||
child: fixed.into(),
|
child: fixed.into(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -120,10 +119,10 @@ fn ellipse_impl(
|
|||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(color) = fill {
|
if let Some(fill) = fill {
|
||||||
ctx.push_into_par(BackgroundNode {
|
ctx.push_into_par(BackgroundNode {
|
||||||
shape: BackgroundShape::Ellipse,
|
shape: BackgroundShape::Ellipse,
|
||||||
fill: Fill::Color(color),
|
fill: Paint::Color(fill),
|
||||||
child: fixed.into(),
|
child: fixed.into(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,7 +16,7 @@ pub use utility::*;
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::color::RgbaColor;
|
use crate::color::{Color, RgbaColor};
|
||||||
use crate::eval::{EvalContext, FuncArgs, Scope, TemplateValue, Value};
|
use crate::eval::{EvalContext, FuncArgs, Scope, TemplateValue, Value};
|
||||||
use crate::exec::{Exec, FontFamily};
|
use crate::exec::{Exec, FontFamily};
|
||||||
use crate::font::{FontStyle, FontWeight, VerticalFontMetric};
|
use crate::font::{FontStyle, FontWeight, VerticalFontMetric};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::exec::{FontState, LineState};
|
use crate::exec::{FontState, LineState};
|
||||||
use crate::font::{FontStretch, FontStyle, FontWeight};
|
use crate::font::{FontStretch, FontStyle, FontWeight};
|
||||||
use crate::layout::Fill;
|
use crate::layout::Paint;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(fill) = fill {
|
if let Some(fill) = fill {
|
||||||
font.fill = Fill::Color(fill);
|
font.fill = Paint::Color(fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(FamilyDef(serif)) = &serif {
|
if let Some(FamilyDef(serif)) = &serif {
|
||||||
@ -244,7 +244,7 @@ fn line_impl(
|
|||||||
// Suppress any existing strikethrough if strength is explicitly zero.
|
// Suppress any existing strikethrough if strength is explicitly zero.
|
||||||
let state = thickness.map_or(true, |s| !s.is_zero()).then(|| {
|
let state = thickness.map_or(true, |s| !s.is_zero()).then(|| {
|
||||||
Rc::new(LineState {
|
Rc::new(LineState {
|
||||||
stroke: stroke.map(Fill::Color),
|
stroke: stroke.map(Paint::Color),
|
||||||
thickness,
|
thickness,
|
||||||
offset,
|
offset,
|
||||||
extent,
|
extent,
|
||||||
|
@ -33,7 +33,7 @@ pub enum Expr {
|
|||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
/// An array expression: `(1, "hi", 12cm)`.
|
/// An array expression: `(1, "hi", 12cm)`.
|
||||||
Array(ArrayExpr),
|
Array(ArrayExpr),
|
||||||
/// A dictionary expression: `(color: #f79143, pattern: dashed)`.
|
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
|
||||||
Dict(DictExpr),
|
Dict(DictExpr),
|
||||||
/// A template expression: `[*Hi* there!]`.
|
/// A template expression: `[*Hi* there!]`.
|
||||||
Template(TemplateExpr),
|
Template(TemplateExpr),
|
||||||
@ -123,7 +123,7 @@ pub struct ArrayExpr {
|
|||||||
pub items: Vec<Expr>,
|
pub items: Vec<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A dictionary expression: `(color: #f79143, pattern: dashed)`.
|
/// A dictionary expression: `(thickness: 3pt, pattern: dashed)`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct DictExpr {
|
pub struct DictExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Test grid layouts.
|
// Test grid layouts.
|
||||||
|
|
||||||
---
|
---
|
||||||
#let rect(width, color) = rect(width: width, height: 2cm, fill: color)
|
#let rect(width, fill) = rect(width: width, height: 2cm, fill: fill)
|
||||||
|
|
||||||
#page!(width: 100pt, height: 140pt)
|
#page!(width: 100pt, height: 140pt)
|
||||||
#grid(
|
#grid(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Test stack layouts.
|
// Test stack layouts.
|
||||||
|
|
||||||
---
|
---
|
||||||
#let rect(width, color) = rect(width: width, height: 1cm, fill: color)
|
#let rect(width, fill) = rect(width: width, height: 1cm, fill: fill)
|
||||||
#stack(
|
#stack(
|
||||||
rect(2cm, rgb("2a631a")),
|
rect(2cm, rgb("2a631a")),
|
||||||
rect(3cm, forest),
|
rect(3cm, forest),
|
||||||
@ -11,7 +11,7 @@
|
|||||||
---
|
---
|
||||||
// Test overflowing stack.
|
// Test overflowing stack.
|
||||||
|
|
||||||
#let rect(width, color) = rect(width: 1cm, height: 0.4cm, fill: color)
|
#let rect(width, fill) = rect(width: 1cm, height: 0.4cm, fill: fill)
|
||||||
#box(height: 0.5cm, stack(
|
#box(height: 0.5cm, stack(
|
||||||
rect(3cm, forest),
|
rect(3cm, forest),
|
||||||
rect(1cm, conifer),
|
rect(1cm, conifer),
|
||||||
|
129
tests/typeset.rs
129
tests/typeset.rs
@ -6,21 +6,18 @@ use std::path::Path;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use image::{GenericImageView, Rgba};
|
use image::{GenericImageView, Rgba};
|
||||||
use tiny_skia::{
|
use tiny_skia as sk;
|
||||||
Color, ColorU8, FillRule, FilterQuality, Paint, Pattern, Pixmap, Rect, SpreadMode,
|
|
||||||
Stroke, Transform,
|
|
||||||
};
|
|
||||||
use ttf_parser::{GlyphId, OutlineBuilder};
|
use ttf_parser::{GlyphId, OutlineBuilder};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use typst::cache::Cache;
|
use typst::cache::Cache;
|
||||||
use typst::color;
|
use typst::color::Color;
|
||||||
use typst::diag::{Diag, DiagSet, Level};
|
use typst::diag::{Diag, DiagSet, Level};
|
||||||
use typst::eval::{eval, EvalContext, FuncArgs, FuncValue, Scope, Value};
|
use typst::eval::{eval, EvalContext, FuncArgs, FuncValue, Scope, Value};
|
||||||
use typst::exec::{exec, State};
|
use typst::exec::{exec, State};
|
||||||
use typst::geom::{self, Length, Point, Sides, Size};
|
use typst::geom::{self, Length, PathElement, Point, Sides, Size};
|
||||||
use typst::image::ImageId;
|
use typst::image::ImageId;
|
||||||
use typst::layout::{layout, Element, Fill, Frame, Shape, Text};
|
use typst::layout::{layout, Element, Frame, Geometry, Paint, Text};
|
||||||
use typst::loading::FsLoader;
|
use typst::loading::FsLoader;
|
||||||
use typst::parse::{parse, LineMap, Scanner};
|
use typst::parse::{parse, LineMap, Scanner};
|
||||||
use typst::syntax::{Location, Pos};
|
use typst::syntax::{Location, Pos};
|
||||||
@ -182,7 +179,7 @@ fn test(
|
|||||||
fs::create_dir_all(&png_path.parent().unwrap()).unwrap();
|
fs::create_dir_all(&png_path.parent().unwrap()).unwrap();
|
||||||
canvas.save_png(png_path).unwrap();
|
canvas.save_png(png_path).unwrap();
|
||||||
|
|
||||||
if let Ok(ref_pixmap) = Pixmap::load_png(ref_path) {
|
if let Ok(ref_pixmap) = sk::Pixmap::load_png(ref_path) {
|
||||||
if canvas != ref_pixmap {
|
if canvas != ref_pixmap {
|
||||||
println!(" Does not match reference image. ❌");
|
println!(" Does not match reference image. ❌");
|
||||||
ok = false;
|
ok = false;
|
||||||
@ -399,7 +396,7 @@ fn print_diag(diag: &Diag, map: &LineMap, lines: u32) {
|
|||||||
println!("{}: {}-{}: {}", diag.level, start, end, diag.message);
|
println!("{}: {}-{}: {}", diag.level, start, end, diag.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(cache: &Cache, frames: &[Rc<Frame>], dpi: f32) -> Pixmap {
|
fn draw(cache: &Cache, frames: &[Rc<Frame>], dpi: f32) -> sk::Pixmap {
|
||||||
let pad = Length::pt(5.0);
|
let pad = Length::pt(5.0);
|
||||||
|
|
||||||
let height = pad + frames.iter().map(|l| l.size.height + pad).sum::<Length>();
|
let height = pad + frames.iter().map(|l| l.size.height + pad).sum::<Length>();
|
||||||
@ -414,16 +411,16 @@ fn draw(cache: &Cache, frames: &[Rc<Frame>], dpi: f32) -> Pixmap {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut canvas = Pixmap::new(pixel_width, pixel_height).unwrap();
|
let mut canvas = sk::Pixmap::new(pixel_width, pixel_height).unwrap();
|
||||||
let ts = Transform::from_scale(dpi, dpi);
|
let ts = sk::Transform::from_scale(dpi, dpi);
|
||||||
canvas.fill(Color::BLACK);
|
canvas.fill(sk::Color::BLACK);
|
||||||
|
|
||||||
let mut origin = Point::splat(pad);
|
let mut origin = Point::splat(pad);
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
let mut paint = Paint::default();
|
let mut paint = sk::Paint::default();
|
||||||
paint.set_color(Color::WHITE);
|
paint.set_color(sk::Color::WHITE);
|
||||||
canvas.fill_rect(
|
canvas.fill_rect(
|
||||||
Rect::from_xywh(
|
sk::Rect::from_xywh(
|
||||||
origin.x.to_pt() as f32,
|
origin.x.to_pt() as f32,
|
||||||
origin.y.to_pt() as f32,
|
origin.y.to_pt() as f32,
|
||||||
frame.size.width.to_pt() as f32,
|
frame.size.width.to_pt() as f32,
|
||||||
@ -442,13 +439,13 @@ fn draw(cache: &Cache, frames: &[Rc<Frame>], dpi: f32) -> Pixmap {
|
|||||||
let ts = ts.pre_translate(x, y);
|
let ts = ts.pre_translate(x, y);
|
||||||
match *element {
|
match *element {
|
||||||
Element::Text(ref text) => {
|
Element::Text(ref text) => {
|
||||||
draw_text(&mut canvas, cache, ts, text);
|
draw_text(&mut canvas, ts, cache, text);
|
||||||
}
|
}
|
||||||
Element::Geometry(ref shape, fill) => {
|
Element::Geometry(ref geometry, paint) => {
|
||||||
draw_geometry(&mut canvas, ts, shape, fill);
|
draw_geometry(&mut canvas, ts, geometry, paint);
|
||||||
}
|
}
|
||||||
Element::Image(id, size) => {
|
Element::Image(id, size) => {
|
||||||
draw_image(&mut canvas, cache, ts, id, size);
|
draw_image(&mut canvas, ts, cache, id, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,7 +456,7 @@ fn draw(cache: &Cache, frames: &[Rc<Frame>], dpi: f32) -> Pixmap {
|
|||||||
canvas
|
canvas
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_text(canvas: &mut Pixmap, cache: &Cache, ts: Transform, text: &Text) {
|
fn draw_text(canvas: &mut sk::Pixmap, ts: sk::Transform, cache: &Cache, text: &Text) {
|
||||||
let ttf = cache.font.get(text.face_id).ttf();
|
let ttf = cache.font.get(text.face_id).ttf();
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
|
|
||||||
@ -493,13 +490,13 @@ fn draw_text(canvas: &mut Pixmap, cache: &Cache, ts: Transform, text: &Text) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, draw normal outline.
|
// Otherwise, draw normal outline.
|
||||||
let mut builder = WrappedPathBuilder(tiny_skia::PathBuilder::new());
|
let mut builder = WrappedPathBuilder(sk::PathBuilder::new());
|
||||||
if ttf.outline_glyph(GlyphId(glyph.id), &mut builder).is_some() {
|
if ttf.outline_glyph(GlyphId(glyph.id), &mut builder).is_some() {
|
||||||
let path = builder.0.finish().unwrap();
|
let path = builder.0.finish().unwrap();
|
||||||
let ts = ts.pre_scale(s, -s);
|
let ts = ts.pre_scale(s, -s);
|
||||||
let mut paint = convert_typst_fill(text.fill);
|
let mut paint = convert_typst_paint(text.fill);
|
||||||
paint.anti_alias = true;
|
paint.anti_alias = true;
|
||||||
canvas.fill_path(&path, &paint, FillRule::default(), ts, None);
|
canvas.fill_path(&path, &paint, sk::FillRule::default(), ts, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,33 +504,38 @@ fn draw_text(canvas: &mut Pixmap, cache: &Cache, ts: Transform, text: &Text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_geometry(canvas: &mut Pixmap, ts: Transform, shape: &Shape, fill: Fill) {
|
fn draw_geometry(
|
||||||
let paint = convert_typst_fill(fill);
|
canvas: &mut sk::Pixmap,
|
||||||
let rule = FillRule::default();
|
ts: sk::Transform,
|
||||||
|
geometry: &Geometry,
|
||||||
|
paint: Paint,
|
||||||
|
) {
|
||||||
|
let paint = convert_typst_paint(paint);
|
||||||
|
let rule = sk::FillRule::default();
|
||||||
|
|
||||||
match *shape {
|
match *geometry {
|
||||||
Shape::Rect(Size { width, height }) => {
|
Geometry::Rect(Size { width, height }) => {
|
||||||
let w = width.to_pt() as f32;
|
let w = width.to_pt() as f32;
|
||||||
let h = height.to_pt() as f32;
|
let h = height.to_pt() as f32;
|
||||||
let rect = Rect::from_xywh(0.0, 0.0, w, h).unwrap();
|
let rect = sk::Rect::from_xywh(0.0, 0.0, w, h).unwrap();
|
||||||
canvas.fill_rect(rect, &paint, ts, None);
|
canvas.fill_rect(rect, &paint, ts, None);
|
||||||
}
|
}
|
||||||
Shape::Ellipse(size) => {
|
Geometry::Ellipse(size) => {
|
||||||
let path = convert_typst_path(&geom::Path::ellipse(size));
|
let path = convert_typst_path(&geom::Path::ellipse(size));
|
||||||
canvas.fill_path(&path, &paint, rule, ts, None);
|
canvas.fill_path(&path, &paint, rule, ts, None);
|
||||||
}
|
}
|
||||||
Shape::Line(target, thickness) => {
|
Geometry::Line(target, thickness) => {
|
||||||
let path = {
|
let path = {
|
||||||
let mut builder = tiny_skia::PathBuilder::new();
|
let mut builder = sk::PathBuilder::new();
|
||||||
builder.line_to(target.x.to_pt() as f32, target.y.to_pt() as f32);
|
builder.line_to(target.x.to_pt() as f32, target.y.to_pt() as f32);
|
||||||
builder.finish().unwrap()
|
builder.finish().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stroke = Stroke::default();
|
let mut stroke = sk::Stroke::default();
|
||||||
stroke.width = thickness.to_pt() as f32;
|
stroke.width = thickness.to_pt() as f32;
|
||||||
canvas.stroke_path(&path, &paint, &stroke, ts, None);
|
canvas.stroke_path(&path, &paint, &stroke, ts, None);
|
||||||
}
|
}
|
||||||
Shape::Path(ref path) => {
|
Geometry::Path(ref path) => {
|
||||||
let path = convert_typst_path(path);
|
let path = convert_typst_path(path);
|
||||||
canvas.fill_path(&path, &paint, rule, ts, None);
|
canvas.fill_path(&path, &paint, rule, ts, None);
|
||||||
}
|
}
|
||||||
@ -541,18 +543,18 @@ fn draw_geometry(canvas: &mut Pixmap, ts: Transform, shape: &Shape, fill: Fill)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_image(
|
fn draw_image(
|
||||||
canvas: &mut Pixmap,
|
canvas: &mut sk::Pixmap,
|
||||||
|
ts: sk::Transform,
|
||||||
cache: &Cache,
|
cache: &Cache,
|
||||||
ts: Transform,
|
|
||||||
id: ImageId,
|
id: ImageId,
|
||||||
size: Size,
|
size: Size,
|
||||||
) {
|
) {
|
||||||
let img = cache.image.get(id);
|
let img = cache.image.get(id);
|
||||||
|
|
||||||
let mut pixmap = Pixmap::new(img.buf.width(), img.buf.height()).unwrap();
|
let mut pixmap = sk::Pixmap::new(img.buf.width(), img.buf.height()).unwrap();
|
||||||
for ((_, _, src), dest) in img.buf.pixels().zip(pixmap.pixels_mut()) {
|
for ((_, _, src), dest) in img.buf.pixels().zip(pixmap.pixels_mut()) {
|
||||||
let Rgba([r, g, b, a]) = src;
|
let Rgba([r, g, b, a]) = src;
|
||||||
*dest = ColorU8::from_rgba(r, g, b, a).premultiply();
|
*dest = sk::ColorU8::from_rgba(r, g, b, a).premultiply();
|
||||||
}
|
}
|
||||||
|
|
||||||
let view_width = size.width.to_pt() as f32;
|
let view_width = size.width.to_pt() as f32;
|
||||||
@ -560,44 +562,41 @@ fn draw_image(
|
|||||||
let scale_x = view_width as f32 / pixmap.width() as f32;
|
let scale_x = view_width as f32 / pixmap.width() as f32;
|
||||||
let scale_y = view_height as f32 / pixmap.height() as f32;
|
let scale_y = view_height as f32 / pixmap.height() as f32;
|
||||||
|
|
||||||
let mut paint = Paint::default();
|
let mut paint = sk::Paint::default();
|
||||||
paint.shader = Pattern::new(
|
paint.shader = sk::Pattern::new(
|
||||||
pixmap.as_ref(),
|
pixmap.as_ref(),
|
||||||
SpreadMode::Pad,
|
sk::SpreadMode::Pad,
|
||||||
FilterQuality::Bilinear,
|
sk::FilterQuality::Bilinear,
|
||||||
1.0,
|
1.0,
|
||||||
Transform::from_row(scale_x, 0.0, 0.0, scale_y, 0.0, 0.0),
|
sk::Transform::from_row(scale_x, 0.0, 0.0, scale_y, 0.0, 0.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let rect = Rect::from_xywh(0.0, 0.0, view_width, view_height).unwrap();
|
let rect = sk::Rect::from_xywh(0.0, 0.0, view_width, view_height).unwrap();
|
||||||
canvas.fill_rect(rect, &paint, ts, None);
|
canvas.fill_rect(rect, &paint, ts, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_typst_fill(fill: Fill) -> Paint<'static> {
|
fn convert_typst_paint(paint: Paint) -> sk::Paint<'static> {
|
||||||
let mut paint = Paint::default();
|
let Paint::Color(Color::Rgba(c)) = paint;
|
||||||
match fill {
|
let mut paint = sk::Paint::default();
|
||||||
Fill::Color(color::Color::Rgba(c)) => {
|
|
||||||
paint.set_color_rgba8(c.r, c.g, c.b, c.a);
|
paint.set_color_rgba8(c.r, c.g, c.b, c.a);
|
||||||
}
|
|
||||||
}
|
|
||||||
paint
|
paint
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_typst_path(path: &geom::Path) -> tiny_skia::Path {
|
fn convert_typst_path(path: &geom::Path) -> sk::Path {
|
||||||
let mut builder = tiny_skia::PathBuilder::new();
|
let mut builder = sk::PathBuilder::new();
|
||||||
let f = |v: Length| v.to_pt() as f32;
|
let f = |v: Length| v.to_pt() as f32;
|
||||||
for elem in &path.0 {
|
for elem in &path.0 {
|
||||||
match elem {
|
match elem {
|
||||||
geom::PathElement::MoveTo(p) => {
|
PathElement::MoveTo(p) => {
|
||||||
builder.move_to(f(p.x), f(p.y));
|
builder.move_to(f(p.x), f(p.y));
|
||||||
}
|
}
|
||||||
geom::PathElement::LineTo(p) => {
|
PathElement::LineTo(p) => {
|
||||||
builder.line_to(f(p.x), f(p.y));
|
builder.line_to(f(p.x), f(p.y));
|
||||||
}
|
}
|
||||||
geom::PathElement::CubicTo(p1, p2, p3) => {
|
PathElement::CubicTo(p1, p2, p3) => {
|
||||||
builder.cubic_to(f(p1.x), f(p1.y), f(p2.x), f(p2.y), f(p3.x), f(p3.y));
|
builder.cubic_to(f(p1.x), f(p1.y), f(p2.x), f(p2.y), f(p3.x), f(p3.y));
|
||||||
}
|
}
|
||||||
geom::PathElement::ClosePath => {
|
PathElement::ClosePath => {
|
||||||
builder.close();
|
builder.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -605,14 +604,14 @@ fn convert_typst_path(path: &geom::Path) -> tiny_skia::Path {
|
|||||||
builder.finish().unwrap()
|
builder.finish().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_usvg_transform(transform: usvg::Transform) -> Transform {
|
fn convert_usvg_transform(transform: usvg::Transform) -> sk::Transform {
|
||||||
let g = |v: f64| v as f32;
|
let g = |v: f64| v as f32;
|
||||||
let usvg::Transform { a, b, c, d, e, f } = transform;
|
let usvg::Transform { a, b, c, d, e, f } = transform;
|
||||||
Transform::from_row(g(a), g(b), g(c), g(d), g(e), g(f))
|
sk::Transform::from_row(g(a), g(b), g(c), g(d), g(e), g(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_usvg_fill(fill: &usvg::Fill) -> (Paint<'static>, FillRule) {
|
fn convert_usvg_fill(fill: &usvg::Fill) -> (sk::Paint<'static>, sk::FillRule) {
|
||||||
let mut paint = Paint::default();
|
let mut paint = sk::Paint::default();
|
||||||
paint.anti_alias = true;
|
paint.anti_alias = true;
|
||||||
|
|
||||||
match fill.paint {
|
match fill.paint {
|
||||||
@ -623,15 +622,15 @@ fn convert_usvg_fill(fill: &usvg::Fill) -> (Paint<'static>, FillRule) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rule = match fill.rule {
|
let rule = match fill.rule {
|
||||||
usvg::FillRule::NonZero => FillRule::Winding,
|
usvg::FillRule::NonZero => sk::FillRule::Winding,
|
||||||
usvg::FillRule::EvenOdd => FillRule::EvenOdd,
|
usvg::FillRule::EvenOdd => sk::FillRule::EvenOdd,
|
||||||
};
|
};
|
||||||
|
|
||||||
(paint, rule)
|
(paint, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_usvg_path(path: &usvg::PathData) -> tiny_skia::Path {
|
fn convert_usvg_path(path: &usvg::PathData) -> sk::Path {
|
||||||
let mut builder = tiny_skia::PathBuilder::new();
|
let mut builder = sk::PathBuilder::new();
|
||||||
let f = |v: f64| v as f32;
|
let f = |v: f64| v as f32;
|
||||||
for seg in path.iter() {
|
for seg in path.iter() {
|
||||||
match *seg {
|
match *seg {
|
||||||
@ -652,7 +651,7 @@ fn convert_usvg_path(path: &usvg::PathData) -> tiny_skia::Path {
|
|||||||
builder.finish().unwrap()
|
builder.finish().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WrappedPathBuilder(tiny_skia::PathBuilder);
|
struct WrappedPathBuilder(sk::PathBuilder);
|
||||||
|
|
||||||
impl OutlineBuilder for WrappedPathBuilder {
|
impl OutlineBuilder for WrappedPathBuilder {
|
||||||
fn move_to(&mut self, x: f32, y: f32) {
|
fn move_to(&mut self, x: f32, y: f32) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user