mirror of
https://github.com/wez/wezterm.git
synced 2024-11-22 22:42:48 +03:00
refactor: extract colr from freetype -> colr.rs
This commit is contained in:
parent
0456719980
commit
01fd28fc02
@ -1,8 +1,8 @@
|
||||
//! Higher level freetype bindings
|
||||
|
||||
use crate::hbwrap::DrawOp;
|
||||
use crate::locator::{FontDataHandle, FontDataSource};
|
||||
use crate::parser::ParsedFont;
|
||||
use crate::rasterizer::colr::DrawOp;
|
||||
use anyhow::{anyhow, Context};
|
||||
use config::{configuration, FreeTypeLoadFlags, FreeTypeLoadTarget};
|
||||
pub use freetype::*;
|
||||
|
@ -4,6 +4,7 @@ use freetype;
|
||||
pub use harfbuzz::*;
|
||||
|
||||
use crate::locator::{FontDataHandle, FontDataSource};
|
||||
use crate::rasterizer::colr::DrawOp;
|
||||
use anyhow::{ensure, Context, Error};
|
||||
use memmap2::{Mmap, MmapOptions};
|
||||
use std::ffi::CStr;
|
||||
@ -753,33 +754,6 @@ impl PaintOp {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DrawOp {
|
||||
MoveTo {
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
LineTo {
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
QuadTo {
|
||||
control_x: f32,
|
||||
control_y: f32,
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
CubicTo {
|
||||
control1_x: f32,
|
||||
control1_y: f32,
|
||||
control2_x: f32,
|
||||
control2_y: f32,
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
ClosePath,
|
||||
}
|
||||
|
||||
impl DrawOp {
|
||||
unsafe fn draw_data(data: *mut ::std::os::raw::c_void) -> &'static mut Vec<DrawOp> {
|
||||
&mut *(data as *mut Vec<DrawOp>)
|
||||
|
223
wezterm-font/src/rasterizer/colr.rs
Normal file
223
wezterm-font/src/rasterizer/colr.rs
Normal file
@ -0,0 +1,223 @@
|
||||
use cairo::{Context, Extend, LinearGradient, Matrix, Operator, RadialGradient};
|
||||
use wezterm_color_types::SrgbaPixel;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ColorStop {
|
||||
pub offset: f32,
|
||||
pub color: SrgbaPixel,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ColorLine {
|
||||
pub color_stops: Vec<ColorStop>,
|
||||
pub extend: Extend,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PaintOp {
|
||||
PushTransform(Matrix),
|
||||
PopTransform,
|
||||
PushClip(Vec<DrawOp>),
|
||||
PopClip,
|
||||
PaintSolid(SrgbaPixel),
|
||||
PaintLinearGradient {
|
||||
x0: f32,
|
||||
y0: f32,
|
||||
x1: f32,
|
||||
y1: f32,
|
||||
x2: f32,
|
||||
y2: f32,
|
||||
color_line: ColorLine,
|
||||
},
|
||||
PaintRadialGradient {
|
||||
x0: f32,
|
||||
y0: f32,
|
||||
r0: f32,
|
||||
x1: f32,
|
||||
y1: f32,
|
||||
r1: f32,
|
||||
color_line: ColorLine,
|
||||
},
|
||||
PaintSweepGradient {
|
||||
x0: f32,
|
||||
y0: f32,
|
||||
start_angle: f32,
|
||||
end_angle: f32,
|
||||
color_line: ColorLine,
|
||||
},
|
||||
PushGroup,
|
||||
PopGroup(Operator),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DrawOp {
|
||||
MoveTo {
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
LineTo {
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
QuadTo {
|
||||
control_x: f32,
|
||||
control_y: f32,
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
CubicTo {
|
||||
control1_x: f32,
|
||||
control1_y: f32,
|
||||
control2_x: f32,
|
||||
control2_y: f32,
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
},
|
||||
ClosePath,
|
||||
}
|
||||
|
||||
pub fn paint_linear_gradient(
|
||||
context: &Context,
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
x2: f64,
|
||||
y2: f64,
|
||||
mut color_line: ColorLine,
|
||||
) -> anyhow::Result<()> {
|
||||
let (min_stop, max_stop) = normalize_color_line(&mut color_line);
|
||||
let anchors = reduce_anchors(ReduceAnchorsIn {
|
||||
x0,
|
||||
y0,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
});
|
||||
|
||||
let xxx0 = anchors.xx0 + min_stop * (anchors.xx1 - anchors.xx0);
|
||||
let yyy0 = anchors.yy0 + min_stop * (anchors.yy1 - anchors.yy0);
|
||||
let xxx1 = anchors.xx0 + max_stop * (anchors.xx1 - anchors.xx0);
|
||||
let yyy1 = anchors.yy0 + max_stop * (anchors.yy1 - anchors.yy0);
|
||||
|
||||
let pattern = LinearGradient::new(xxx0, yyy0, xxx1, yyy1);
|
||||
pattern.set_extend(color_line.extend);
|
||||
|
||||
for stop in &color_line.color_stops {
|
||||
let (r, g, b, a) = stop.color.as_srgba_tuple();
|
||||
pattern.add_color_stop_rgba(stop.offset.into(), r.into(), g.into(), b.into(), a.into());
|
||||
}
|
||||
|
||||
context.set_source(pattern)?;
|
||||
context.paint()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn paint_radial_gradient(
|
||||
context: &Context,
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
r0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
r1: f64,
|
||||
mut color_line: ColorLine,
|
||||
) -> anyhow::Result<()> {
|
||||
let (min_stop, max_stop) = normalize_color_line(&mut color_line);
|
||||
|
||||
let xx0 = x0 + min_stop * (x1 - x0);
|
||||
let yy0 = y0 + min_stop * (y1 - y0);
|
||||
let xx1 = x0 + max_stop * (x1 - x0);
|
||||
let yy1 = y0 + max_stop * (y1 - y0);
|
||||
let rr0 = r0 + min_stop * (r1 - r0);
|
||||
let rr1 = r0 + max_stop * (r1 - r0);
|
||||
|
||||
let pattern = RadialGradient::new(xx0, yy0, rr0, xx1, yy1, rr1);
|
||||
pattern.set_extend(color_line.extend);
|
||||
|
||||
for stop in &color_line.color_stops {
|
||||
let (r, g, b, a) = stop.color.as_srgba_tuple();
|
||||
pattern.add_color_stop_rgba(stop.offset.into(), r.into(), g.into(), b.into(), a.into());
|
||||
}
|
||||
|
||||
context.set_source(pattern)?;
|
||||
context.paint()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn normalize_color_line(color_line: &mut ColorLine) -> (f64, f64) {
|
||||
let mut smallest = color_line.color_stops[0].offset;
|
||||
let mut largest = smallest;
|
||||
|
||||
for stop in &color_line.color_stops[1..] {
|
||||
smallest = smallest.min(stop.offset);
|
||||
largest = largest.max(stop.offset);
|
||||
}
|
||||
|
||||
if smallest != largest {
|
||||
for stop in &mut color_line.color_stops {
|
||||
stop.offset = (stop.offset - smallest) / (largest - smallest);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: hb-cairo-utils will call back out to some other state
|
||||
// to fill in the color when is_foreground is true, defaulting
|
||||
// to black with alpha varying by the alpha channel of the
|
||||
// color value in the stop. Do we need to do something like
|
||||
// that here?
|
||||
|
||||
(smallest as f64, largest as f64)
|
||||
}
|
||||
|
||||
struct ReduceAnchorsIn {
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
x2: f64,
|
||||
y2: f64,
|
||||
}
|
||||
|
||||
struct ReduceAnchorsOut {
|
||||
xx0: f64,
|
||||
yy0: f64,
|
||||
xx1: f64,
|
||||
yy1: f64,
|
||||
}
|
||||
|
||||
fn reduce_anchors(
|
||||
ReduceAnchorsIn {
|
||||
x0,
|
||||
y0,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
}: ReduceAnchorsIn,
|
||||
) -> ReduceAnchorsOut {
|
||||
let q2x = x2 - x0;
|
||||
let q2y = y2 - y0;
|
||||
let q1x = x1 - x0;
|
||||
let q1y = y1 - y0;
|
||||
|
||||
let s = q2x * q2x + q2y * q2y;
|
||||
if s < 0.000001 {
|
||||
return ReduceAnchorsOut {
|
||||
xx0: x0,
|
||||
yy0: y0,
|
||||
xx1: x1,
|
||||
yy1: y1,
|
||||
};
|
||||
}
|
||||
|
||||
let k = (q2x * q1x + q2y * q1y) / s;
|
||||
ReduceAnchorsOut {
|
||||
xx0: x0,
|
||||
yy0: y0,
|
||||
xx1: x1 - k * q2x,
|
||||
yy1: y1 - k * q2y,
|
||||
}
|
||||
}
|
@ -3,8 +3,10 @@ use crate::ftwrap::{
|
||||
FT_Fixed, FT_Get_Colorline_Stops, FT_Int32, FT_PaintExtend, IsSvg, SelectedFontSize,
|
||||
FT_LOAD_NO_HINTING,
|
||||
};
|
||||
use crate::hbwrap::DrawOp;
|
||||
use crate::parser::ParsedFont;
|
||||
use crate::rasterizer::colr::{
|
||||
paint_linear_gradient, paint_radial_gradient, ColorLine, ColorStop, DrawOp, PaintOp,
|
||||
};
|
||||
use crate::rasterizer::harfbuzz::{argb_to_rgba, HarfbuzzRasterizer};
|
||||
use crate::rasterizer::{FontRasterizer, FAKE_ITALIC_SKEW};
|
||||
use crate::units::*;
|
||||
@ -13,10 +15,7 @@ use ::freetype::{
|
||||
FT_Color_Root_Transform, FT_GlyphSlotRec_, FT_Matrix, FT_Opaque_Paint_, FT_PaintFormat_,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use cairo::{
|
||||
Content, Context, Extend, Format, ImageSurface, LinearGradient, Matrix, Operator,
|
||||
RadialGradient, RecordingSurface,
|
||||
};
|
||||
use cairo::{Content, Context, Extend, Format, ImageSurface, Matrix, Operator, RecordingSurface};
|
||||
use config::{DisplayPixelGeometry, FreeTypeLoadFlags, FreeTypeLoadTarget};
|
||||
use std::cell::RefCell;
|
||||
use std::f64::consts::PI;
|
||||
@ -706,54 +705,6 @@ impl<'a> Walker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ColorStop {
|
||||
pub offset: f32,
|
||||
pub color: SrgbaPixel,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ColorLine {
|
||||
pub color_stops: Vec<ColorStop>,
|
||||
pub extend: Extend,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PaintOp {
|
||||
PushTransform(Matrix),
|
||||
PopTransform,
|
||||
PushClip(Vec<DrawOp>),
|
||||
PopClip,
|
||||
PaintSolid(SrgbaPixel),
|
||||
PaintLinearGradient {
|
||||
x0: f32,
|
||||
y0: f32,
|
||||
x1: f32,
|
||||
y1: f32,
|
||||
x2: f32,
|
||||
y2: f32,
|
||||
color_line: ColorLine,
|
||||
},
|
||||
PaintRadialGradient {
|
||||
x0: f32,
|
||||
y0: f32,
|
||||
r0: f32,
|
||||
x1: f32,
|
||||
y1: f32,
|
||||
r1: f32,
|
||||
color_line: ColorLine,
|
||||
},
|
||||
PaintSweepGradient {
|
||||
x0: f32,
|
||||
y0: f32,
|
||||
start_angle: f32,
|
||||
end_angle: f32,
|
||||
color_line: ColorLine,
|
||||
},
|
||||
PushGroup,
|
||||
PopGroup(Operator),
|
||||
}
|
||||
|
||||
fn affine2x3_to_matrix(t: FT_Affine23) -> Matrix {
|
||||
Matrix::new(
|
||||
t.xx.to_num(),
|
||||
@ -931,149 +882,3 @@ fn apply_draw_ops_to_context(ops: &[DrawOp], context: &Context) -> anyhow::Resul
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn normalize_color_line(color_line: &mut ColorLine) -> (f64, f64) {
|
||||
let mut smallest = color_line.color_stops[0].offset;
|
||||
let mut largest = smallest;
|
||||
|
||||
for stop in &color_line.color_stops[1..] {
|
||||
smallest = smallest.min(stop.offset);
|
||||
largest = largest.max(stop.offset);
|
||||
}
|
||||
|
||||
if smallest != largest {
|
||||
for stop in &mut color_line.color_stops {
|
||||
stop.offset = (stop.offset - smallest) / (largest - smallest);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: hb-cairo-utils will call back out to some other state
|
||||
// to fill in the color when is_foreground is true, defaulting
|
||||
// to black with alpha varying by the alpha channel of the
|
||||
// color value in the stop. Do we need to do something like
|
||||
// that here?
|
||||
|
||||
(smallest as f64, largest as f64)
|
||||
}
|
||||
|
||||
struct ReduceAnchorsIn {
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
x2: f64,
|
||||
y2: f64,
|
||||
}
|
||||
|
||||
struct ReduceAnchorsOut {
|
||||
xx0: f64,
|
||||
yy0: f64,
|
||||
xx1: f64,
|
||||
yy1: f64,
|
||||
}
|
||||
|
||||
fn reduce_anchors(
|
||||
ReduceAnchorsIn {
|
||||
x0,
|
||||
y0,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
}: ReduceAnchorsIn,
|
||||
) -> ReduceAnchorsOut {
|
||||
let q2x = x2 - x0;
|
||||
let q2y = y2 - y0;
|
||||
let q1x = x1 - x0;
|
||||
let q1y = y1 - y0;
|
||||
|
||||
let s = q2x * q2x + q2y * q2y;
|
||||
if s < 0.000001 {
|
||||
return ReduceAnchorsOut {
|
||||
xx0: x0,
|
||||
yy0: y0,
|
||||
xx1: x1,
|
||||
yy1: y1,
|
||||
};
|
||||
}
|
||||
|
||||
let k = (q2x * q1x + q2y * q1y) / s;
|
||||
ReduceAnchorsOut {
|
||||
xx0: x0,
|
||||
yy0: y0,
|
||||
xx1: x1 - k * q2x,
|
||||
yy1: y1 - k * q2y,
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_linear_gradient(
|
||||
context: &Context,
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
x2: f64,
|
||||
y2: f64,
|
||||
mut color_line: ColorLine,
|
||||
) -> anyhow::Result<()> {
|
||||
let (min_stop, max_stop) = normalize_color_line(&mut color_line);
|
||||
let anchors = reduce_anchors(ReduceAnchorsIn {
|
||||
x0,
|
||||
y0,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
});
|
||||
|
||||
let xxx0 = anchors.xx0 + min_stop * (anchors.xx1 - anchors.xx0);
|
||||
let yyy0 = anchors.yy0 + min_stop * (anchors.yy1 - anchors.yy0);
|
||||
let xxx1 = anchors.xx0 + max_stop * (anchors.xx1 - anchors.xx0);
|
||||
let yyy1 = anchors.yy0 + max_stop * (anchors.yy1 - anchors.yy0);
|
||||
|
||||
let pattern = LinearGradient::new(xxx0, yyy0, xxx1, yyy1);
|
||||
pattern.set_extend(color_line.extend);
|
||||
|
||||
for stop in &color_line.color_stops {
|
||||
let (r, g, b, a) = stop.color.as_srgba_tuple();
|
||||
pattern.add_color_stop_rgba(stop.offset.into(), r.into(), g.into(), b.into(), a.into());
|
||||
}
|
||||
|
||||
context.set_source(pattern)?;
|
||||
context.paint()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn paint_radial_gradient(
|
||||
context: &Context,
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
r0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
r1: f64,
|
||||
mut color_line: ColorLine,
|
||||
) -> anyhow::Result<()> {
|
||||
let (min_stop, max_stop) = normalize_color_line(&mut color_line);
|
||||
|
||||
let xx0 = x0 + min_stop * (x1 - x0);
|
||||
let yy0 = y0 + min_stop * (y1 - y0);
|
||||
let xx1 = x0 + max_stop * (x1 - x0);
|
||||
let yy1 = y0 + max_stop * (y1 - y0);
|
||||
let rr0 = r0 + min_stop * (r1 - r0);
|
||||
let rr1 = r0 + max_stop * (r1 - r0);
|
||||
|
||||
let pattern = RadialGradient::new(xx0, yy0, rr0, xx1, yy1, rr1);
|
||||
pattern.set_extend(color_line.extend);
|
||||
|
||||
for stop in &color_line.color_stops {
|
||||
let (r, g, b, a) = stop.color.as_srgba_tuple();
|
||||
pattern.add_color_stop_rgba(stop.offset.into(), r.into(), g.into(), b.into(), a.into());
|
||||
}
|
||||
|
||||
context.set_source(pattern)?;
|
||||
context.paint()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::hbwrap::{
|
||||
hb_color, hb_color_get_alpha, hb_color_get_blue, hb_color_get_green, hb_color_get_red,
|
||||
hb_color_t, hb_paint_composite_mode_t, hb_paint_extend_t, hb_tag_to_string, ColorLine, DrawOp,
|
||||
Font, PaintOp, IS_PNG,
|
||||
hb_color_t, hb_paint_composite_mode_t, hb_paint_extend_t, hb_tag_to_string, ColorLine, Font,
|
||||
PaintOp, IS_PNG,
|
||||
};
|
||||
use crate::rasterizer::colr::DrawOp;
|
||||
use crate::rasterizer::FAKE_ITALIC_SKEW;
|
||||
use crate::units::PixelLength;
|
||||
use crate::{FontRasterizer, ParsedFont, RasterizedGlyph};
|
||||
|
@ -7,6 +7,7 @@ use image::{ImageBuffer, Rgba};
|
||||
/// italics
|
||||
pub(crate) const FAKE_ITALIC_SKEW: f64 = 0.2;
|
||||
|
||||
pub mod colr;
|
||||
pub mod freetype;
|
||||
pub mod harfbuzz;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user