mirror of
https://github.com/typst/typst
synced 2025-05-19 03:25:27 +08:00
Text colors 🦩 (#18)
This commit is contained in:
parent
898dc38ec1
commit
6cb9fe9064
@ -178,6 +178,7 @@ impl<'a> ExecContext<'a> {
|
||||
font_size: self.state.font.font_size(),
|
||||
top_edge: self.state.font.top_edge,
|
||||
bottom_edge: self.state.font.bottom_edge,
|
||||
color: self.state.font.color,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,9 @@ use std::rc::Rc;
|
||||
|
||||
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
|
||||
|
||||
use crate::color::{Color, RgbaColor};
|
||||
use crate::geom::*;
|
||||
use crate::layout::VerticalFontMetric;
|
||||
use crate::layout::{Fill, VerticalFontMetric};
|
||||
use crate::paper::{Paper, PaperClass, PAPER_A4};
|
||||
|
||||
/// The evaluation state.
|
||||
@ -115,6 +116,8 @@ pub struct FontState {
|
||||
/// Whether the emphasis toggle is active or inactive. This determines
|
||||
/// whether the next `_` makes italic or non-italic.
|
||||
pub emph: bool,
|
||||
/// The glyph fill color / texture.
|
||||
pub color: Fill,
|
||||
}
|
||||
|
||||
impl FontState {
|
||||
@ -149,6 +152,7 @@ impl Default for FontState {
|
||||
scale: Linear::ONE,
|
||||
strong: false,
|
||||
emph: false,
|
||||
color: Fill::Color(Color::Rgba(RgbaColor::BLACK)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +133,22 @@ impl<'a> PdfExporter<'a> {
|
||||
// do that, we need to remember the active face.
|
||||
let mut face = FaceId::MAX;
|
||||
let mut size = Length::ZERO;
|
||||
let mut fill: Option<Fill> = None;
|
||||
let mut change_color = |content: &mut Content, new_fill: Fill| {
|
||||
if fill != Some(new_fill) {
|
||||
match new_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,
|
||||
);
|
||||
}
|
||||
Fill::Image(_) => todo!(),
|
||||
}
|
||||
fill = Some(new_fill);
|
||||
}
|
||||
};
|
||||
|
||||
for (pos, element) in &page.elements {
|
||||
let x = pos.x.to_pt() as f32;
|
||||
@ -152,17 +168,7 @@ impl<'a> PdfExporter<'a> {
|
||||
|
||||
Element::Geometry(geometry) => {
|
||||
content.save_state();
|
||||
|
||||
match geometry.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,
|
||||
);
|
||||
}
|
||||
Fill::Image(_) => todo!(),
|
||||
}
|
||||
change_color(&mut content, geometry.fill);
|
||||
|
||||
match &geometry.shape {
|
||||
Shape::Rect(r) => {
|
||||
@ -179,9 +185,12 @@ impl<'a> PdfExporter<'a> {
|
||||
}
|
||||
|
||||
Element::Text(shaped) => {
|
||||
change_color(&mut content, shaped.color);
|
||||
|
||||
let mut text = content.text();
|
||||
|
||||
// Check if we need to issue a font switching action.
|
||||
// Then, also check if we need to
|
||||
// issue a font switching action.
|
||||
if shaped.face != face || shaped.font_size != size {
|
||||
face = shaped.face;
|
||||
size = shaped.font_size;
|
||||
|
@ -11,7 +11,7 @@ use ttf_parser::{Face, GlyphId};
|
||||
|
||||
use crate::env::FontLoader;
|
||||
use crate::geom::{Dir, Length, Point, Size};
|
||||
use crate::layout::{Element, Frame};
|
||||
use crate::layout::{Element, Fill, Frame};
|
||||
|
||||
/// A shaped run of text.
|
||||
#[derive(Clone, PartialEq)]
|
||||
@ -27,17 +27,20 @@ pub struct Shaped {
|
||||
pub offsets: Vec<Length>,
|
||||
/// The font size.
|
||||
pub font_size: Length,
|
||||
/// The glyph fill color / texture.
|
||||
pub color: Fill,
|
||||
}
|
||||
|
||||
impl Shaped {
|
||||
/// Create a new shape run with empty `text`, `glyphs` and `offsets`.
|
||||
pub fn new(face: FaceId, font_size: Length) -> Self {
|
||||
pub fn new(face: FaceId, font_size: Length, color: Fill) -> Self {
|
||||
Self {
|
||||
text: String::new(),
|
||||
face,
|
||||
glyphs: vec![],
|
||||
offsets: vec![],
|
||||
font_size,
|
||||
color: color,
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,10 +103,11 @@ pub fn shape(
|
||||
font_size: Length,
|
||||
top_edge: VerticalFontMetric,
|
||||
bottom_edge: VerticalFontMetric,
|
||||
color: Fill,
|
||||
loader: &mut FontLoader,
|
||||
) -> Frame {
|
||||
let mut frame = Frame::new(Size::new(Length::ZERO, Length::ZERO));
|
||||
let mut shaped = Shaped::new(FaceId::MAX, font_size);
|
||||
let mut shaped = Shaped::new(FaceId::MAX, font_size, color);
|
||||
let mut width = Length::ZERO;
|
||||
let mut top = Length::ZERO;
|
||||
let mut bottom = Length::ZERO;
|
||||
@ -133,7 +137,7 @@ pub fn shape(
|
||||
if shaped.face != id {
|
||||
place(&mut frame, shaped, width, top, bottom);
|
||||
|
||||
shaped = Shaped::new(id, font_size);
|
||||
shaped = Shaped::new(id, font_size, color);
|
||||
width = Length::ZERO;
|
||||
top = convert(f64::from(lookup_metric(face, top_edge)));
|
||||
bottom = convert(f64::from(lookup_metric(face, bottom_edge)));
|
||||
|
@ -24,6 +24,8 @@ pub struct TextNode {
|
||||
pub top_edge: VerticalFontMetric,
|
||||
/// The bottom end of the text bounding box.
|
||||
pub bottom_edge: VerticalFontMetric,
|
||||
/// The glyph fill.
|
||||
pub color: Fill,
|
||||
}
|
||||
|
||||
impl Layout for TextNode {
|
||||
@ -37,6 +39,7 @@ impl Layout for TextNode {
|
||||
self.font_size,
|
||||
self.top_edge,
|
||||
self.bottom_edge,
|
||||
self.color,
|
||||
&mut ctx.env.fonts,
|
||||
),
|
||||
self.aligns,
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::layout::Fill;
|
||||
use fontdock::{FontStretch, FontStyle, FontWeight};
|
||||
|
||||
use super::*;
|
||||
@ -15,6 +16,7 @@ use super::*;
|
||||
/// - Font Stretch: `stretch`, of type `relative`, between 0.5 and 2.0.
|
||||
/// - Top edge of the font: `top-edge`, of type `vertical-font-metric`.
|
||||
/// - Bottom edge of the font: `bottom-edge`, of type `vertical-font-metric`.
|
||||
/// - Fill color the glyphs: `color`, of type `color`.
|
||||
/// - Serif family definition: `serif`, of type `font-familiy-list`.
|
||||
/// - Sans-serif family definition: `sans-serif`, of type `font-familiy-list`.
|
||||
/// - Monospace family definition: `monospace`, of type `font-familiy-list`.
|
||||
@ -62,6 +64,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let stretch = args.get(ctx, "stretch");
|
||||
let top_edge = args.get(ctx, "top-edge");
|
||||
let bottom_edge = args.get(ctx, "bottom-edge");
|
||||
let color = args.get(ctx, "color");
|
||||
let serif = args.get(ctx, "serif");
|
||||
let sans_serif = args.get(ctx, "sans-serif");
|
||||
let monospace = args.get(ctx, "monospace");
|
||||
@ -105,6 +108,10 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
ctx.state.font.bottom_edge = bottom_edge;
|
||||
}
|
||||
|
||||
if let Some(color) = color {
|
||||
ctx.state.font.color = Fill::Color(color);
|
||||
}
|
||||
|
||||
for (variant, arg) in &[
|
||||
(FontFamily::Serif, &serif),
|
||||
(FontFamily::SansSerif, &sans_serif),
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 10 KiB |
@ -31,6 +31,9 @@ Emoji: 🐪, 🌋, 🏞
|
||||
∫ 𝛼 + 3𝛽 d𝑡
|
||||
]
|
||||
|
||||
// Colors.
|
||||
#font(color: #239DAD)[This is #font(color: #FA644B)[way more] colorful.]
|
||||
|
||||
---
|
||||
// Test top and bottom edge.
|
||||
|
||||
|
@ -426,7 +426,7 @@ fn draw_text(env: &Env, canvas: &mut Canvas, pos: Point, shaped: &Shaped) {
|
||||
.transform(&Transform::from_row(scale, 0.0, 0.0, -scale, x, y).unwrap())
|
||||
.unwrap();
|
||||
|
||||
let mut paint = Paint::default();
|
||||
let mut paint = paint_from_fill(shaped.color);
|
||||
paint.anti_alias = true;
|
||||
|
||||
canvas.fill_path(&placed, &paint, FillRule::default());
|
||||
@ -438,13 +438,7 @@ fn draw_geometry(_: &Env, canvas: &mut Canvas, pos: Point, element: &Geometry) {
|
||||
let x = pos.x.to_pt() as f32;
|
||||
let y = pos.y.to_pt() as f32;
|
||||
|
||||
let mut paint = Paint::default();
|
||||
match &element.fill {
|
||||
Fill::Color(c) => match c {
|
||||
typst::color::Color::Rgba(c) => paint.set_color_rgba8(c.r, c.g, c.b, c.a),
|
||||
},
|
||||
Fill::Image(_) => todo!(),
|
||||
};
|
||||
let paint = paint_from_fill(element.fill);
|
||||
|
||||
match &element.shape {
|
||||
Shape::Rect(s) => {
|
||||
@ -454,6 +448,18 @@ fn draw_geometry(_: &Env, canvas: &mut Canvas, pos: Point, element: &Geometry) {
|
||||
};
|
||||
}
|
||||
|
||||
fn paint_from_fill(fill: Fill) -> Paint<'static> {
|
||||
let mut paint = Paint::default();
|
||||
match fill {
|
||||
Fill::Color(c) => match c {
|
||||
typst::color::Color::Rgba(c) => paint.set_color_rgba8(c.r, c.g, c.b, c.a),
|
||||
},
|
||||
Fill::Image(_) => todo!(),
|
||||
}
|
||||
|
||||
paint
|
||||
}
|
||||
|
||||
fn draw_image(env: &Env, canvas: &mut Canvas, pos: Point, element: &Image) {
|
||||
let img = &env.resources.loaded::<ImageResource>(element.res);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user