From 4b1f655a8391d8b806c8fe9a4c6503c728d02d72 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 4 Mar 2025 23:56:01 -0700 Subject: [PATCH] [fontations] Implement LinearGradients --- src/fontations/lib.rs | 81 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/src/fontations/lib.rs b/src/fontations/lib.rs index de245ba2e..5ef8a94a6 100644 --- a/src/fontations/lib.rs +++ b/src/fontations/lib.rs @@ -10,7 +10,7 @@ use read_fonts::tables::cpal::ColorRecord; use read_fonts::TableProvider; use skrifa::charmap::Charmap; use skrifa::charmap::MapVariant::Variant; -use skrifa::color::{Brush, ColorGlyphCollection, ColorPainter, CompositeMode, Transform}; +use skrifa::color::{Brush, ColorGlyphCollection, ColorPainter, ColorStop, CompositeMode, Extend, Transform}; use skrifa::font::FontRef; use skrifa::instance::{Location, NormalizedCoord, Size}; use skrifa::metrics::BoundingBox; @@ -346,6 +346,53 @@ impl HbColorPainter { } } +struct ColorLineData<'a> { + color_stops: &'a [ColorStop], + extend: Extend, +} +extern "C" fn _hb_fontations_get_color_stops ( + _color_line: *mut hb_color_line_t, + color_line_data: *mut ::std::os::raw::c_void, + start: ::std::os::raw::c_uint, + count_out: *mut ::std::os::raw::c_uint, + color_stops_out: *mut hb_color_stop_t, + user_data: *mut ::std::os::raw::c_void, +) -> ::std::os::raw::c_uint +{ + let color_painter = unsafe { &*(color_line_data as *const HbColorPainter) }; + let color_line_data = unsafe { &*(user_data as *const ColorLineData) }; + let color_stops = &color_line_data.color_stops; + if count_out.is_null() { + return color_stops.len() as u32; + } + let count = unsafe { *count_out }; + for i in 0..count { + let stop = color_stops.get(start as usize + i as usize); + if stop.is_none() { + unsafe { *count_out = i; }; + return color_stops.len() as u32; + } + let stop = stop.unwrap(); + unsafe { + *(color_stops_out.offset(i as isize)) = hb_color_stop_t { + offset: stop.offset, + color: color_painter.lookup_color(stop.palette_index, stop.alpha), + is_foreground: (stop.palette_index == 0xFFFF) as hb_bool_t, + }; + } + } + return color_stops.len() as u32; +} +extern "C" fn _hb_fontations_get_extend ( + _color_line: *mut hb_color_line_t, + color_line_data: *mut ::std::os::raw::c_void, + _user_data: *mut ::std::os::raw::c_void, +) -> hb_paint_extend_t +{ + let color_line_data = unsafe { &*(color_line_data as *const ColorLineData) }; + color_line_data.extend as hb_paint_extend_t // They are the same +} + impl ColorPainter for HbColorPainter { fn push_transform(&mut self, transform: Transform) { unsafe { @@ -421,6 +468,34 @@ impl ColorPainter for HbColorPainter { ); } } + Brush::LinearGradient { + color_stops, + extend, + p0, + p1, + } => { + let color_stops = ColorLineData { color_stops: &color_stops, extend }; + unsafe { + let mut cl = std::mem::zeroed::(); + cl.data = self as *mut HbColorPainter as *mut ::std::os::raw::c_void; + cl.get_color_stops = Some(_hb_fontations_get_color_stops); + cl.get_color_stops_user_data = &color_stops as *const ColorLineData as *mut ::std::os::raw::c_void; + cl.get_extend = Some(_hb_fontations_get_extend); + cl.get_extend_user_data = &extend as *const Extend as *mut ::std::os::raw::c_void; + + hb_paint_linear_gradient( + self.paint_funcs, + self.paint_data, + &mut cl, + p0.x, + p0.y, + p1.x, + p1.y, + p1.x, // TODO: Where's p2? + p1.y, // TODO: Where's p2? + ); + } + } _ => {} } } @@ -435,7 +510,7 @@ impl ColorPainter for HbColorPainter { if mode.is_none() { return; } - let mode = mode.unwrap() as hb_paint_composite_mode_t; + let mode = mode.unwrap() as hb_paint_composite_mode_t; // They are the same unsafe { hb_paint_pop_group(self.paint_funcs, self.paint_data, mode); } @@ -469,7 +544,7 @@ extern "C" fn _hb_fontations_paint_glyph( let mut color_records = Box::<[ColorRecord]>::default(); if cpal.is_ok() { let cpal = cpal.unwrap(); - // fontations doesn't seem to provide a way to access palettes + // TODO fontations doesn't seem to provide a way to access palettes // really. Just assume the first palette starts at the beginning // of the color records array. let color_records_array = cpal.color_records_array();