1
1
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:
Wez Furlong 2023-08-21 09:19:22 -07:00
parent 0456719980
commit 01fd28fc02
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
6 changed files with 233 additions and 229 deletions

View File

@ -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::*;

View File

@ -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>)

View 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,
}
}

View File

@ -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(())
}

View File

@ -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};

View File

@ -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;