mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 21:44:57 +00:00
Type: a COLR glyph whose radial gradient draws no circle draws nothing
A radial gradient whose circles both have the same negative radius (as a variable font's instance can give) draws no circle. A glyph painted with only that gradient was read as no colour glyph, so layout drew its outline instead. It is now colour art that draws nothing.
This commit is contained in:
+10
-2
@@ -148,6 +148,9 @@ struct Tree<'a> {
|
||||
painted: Option<Rect>,
|
||||
/// It paints with the foreground colour (palette index 0xFFFF).
|
||||
foreground_used: bool,
|
||||
/// A fill draws nothing (a radial gradient none of whose circles has a positive radius), so a
|
||||
/// glyph with nothing else is colour art that draws nothing, not its outline.
|
||||
drew_nothing: bool,
|
||||
}
|
||||
|
||||
impl<'a> Tree<'a> {
|
||||
@@ -166,6 +169,7 @@ impl<'a> Tree<'a> {
|
||||
too_large: false,
|
||||
painted: None,
|
||||
foreground_used: false,
|
||||
drew_nothing: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +258,7 @@ impl<'a> Tree<'a> {
|
||||
self.close();
|
||||
}
|
||||
let root = self.groups.pop()?;
|
||||
if root.children.is_empty() {
|
||||
if root.children.is_empty() && !self.drew_nothing {
|
||||
return None;
|
||||
}
|
||||
Some(Arc::new(Node::group(NO_ID, root.children)))
|
||||
@@ -314,7 +318,11 @@ impl<'a> Tree<'a> {
|
||||
self.unsupported.get_or_insert("a repeating or reflecting gradient with a stop missing from the palette");
|
||||
return None;
|
||||
}
|
||||
let (c0, r0, c1, r1, mut stops) = non_negative_radii(point(*c0), f64::from(*r0), point(*c1), f64::from(*r1), line, *extend)?;
|
||||
let Some((c0, r0, c1, r1, mut stops)) = non_negative_radii(point(*c0), f64::from(*r0), point(*c1), f64::from(*r1), line, *extend)
|
||||
else {
|
||||
self.drew_nothing = true;
|
||||
return None;
|
||||
};
|
||||
let concentric = (c0 - c1).hypot() < 1e-6;
|
||||
if (r0 > 1e-6 && !concentric) || r1 <= r0 || (c0 - c1).hypot() >= r1 {
|
||||
self.unsupported.get_or_insert("a radial gradient from a circle");
|
||||
|
||||
@@ -1939,6 +1939,12 @@ pub fn colr_variable_font() -> Option<Vec<u8>> {
|
||||
with_colr(&variable_font()?, family_names(COLR_VARIABLE_FAMILY, &axis_names)?, &colr)
|
||||
}
|
||||
|
||||
/// [`variable_font`] (one weight axis, 400 to 700) as `family` with `colr` and [`colr_font`]'s
|
||||
/// palette. `None` when it can't be built.
|
||||
pub fn colr_variable_font_with(family: &str, colr: &write_fonts::tables::colr::Colr) -> Option<Vec<u8>> {
|
||||
with_colr(&variable_font()?, family_names(family, &[])?, colr)
|
||||
}
|
||||
|
||||
/// A `name` table for Regular of `family`, with `more` records.
|
||||
fn family_names(family: &str, more: &[(u16, &str)]) -> Option<Vec<u8>> {
|
||||
let ps = family.replace(' ', "");
|
||||
|
||||
@@ -467,6 +467,38 @@ fn an_image_of_a_radial_gradient_with_a_stop_past_its_circle_of_radius_0_draws_f
|
||||
}
|
||||
}
|
||||
|
||||
/// A radial gradient whose circles both have the same negative radius at a variable font's
|
||||
/// instance draws no circle, so a glyph painted with only that gradient is colour art that draws
|
||||
/// nothing, not its outline. The radii are 10 at the default weight and -10 at 700.
|
||||
#[test]
|
||||
fn a_radial_gradient_with_no_circle_drawn_leaves_the_glyph_empty() {
|
||||
use write_fonts::tables::colr::{BaseGlyphList, BaseGlyphPaint, Colr, Extend, VarColorLine, VarColorStop};
|
||||
use write_fonts::tables::variations::{ItemVariationData, ItemVariationStore, RegionAxisCoordinates, VariationRegion, VariationRegionList};
|
||||
use write_fonts::types::{F2Dot14, FWord, GlyphId16, UfWord};
|
||||
let bytes = colr_font(false).unwrap();
|
||||
let read = skrifa::FontRef::new(&bytes).unwrap();
|
||||
let gid = |ch| GlyphId16::new(u16::try_from(read.charmap().map(ch).unwrap().to_u32()).unwrap());
|
||||
let (one, fixed) = (F2Dot14::from_f32(1.0), 0xFFFF_FFFF);
|
||||
let line =
|
||||
VarColorLine::new(Extend::Pad, 2, vec![VarColorStop::new(F2Dot14::from_f32(0.0), 0, one, fixed), VarColorStop::new(one, 1, one, fixed)]);
|
||||
let w = FWord::new;
|
||||
let radial = ColrPaint::var_radial_gradient(line, w(290), w(330), UfWord::new(10), w(290), w(330), UfWord::new(10), 0);
|
||||
let mut colr = Colr::new(0, None, None, 0);
|
||||
colr.base_glyph_list = Some(BaseGlyphList::new(1, vec![BaseGlyphPaint::new(gid(COLOUR_CHAR), ColrPaint::glyph(radial, gid('O')))])).into();
|
||||
// One 16-bit delta for each of x0, y0, r0, x1, y1 and r1, at full weight.
|
||||
let deltas: Vec<u8> = [0i16, 0, -20, 0, 0, -20].iter().flat_map(|d| d.to_be_bytes()).collect();
|
||||
let region = VariationRegion::new(vec![RegionAxisCoordinates::new(F2Dot14::from_f32(0.0), one, one)]);
|
||||
let data = ItemVariationData::new(6, 1, vec![0], deltas);
|
||||
colr.item_variation_store = Some(ItemVariationStore::new(VariationRegionList::new(1, vec![region]), vec![Some(data)])).into();
|
||||
let font = crate::test_fonts::colr_variable_font_with("Colrtest No Circle", &colr).unwrap();
|
||||
let font = skrifa::FontRef::new(&font).unwrap();
|
||||
let bold = font.axes().location([("wght", 700.0)]);
|
||||
let Some(ColourContent::Art(root)) = colour_glyph(&font, (&bold).into(), 1000.0, u32::from(gid(COLOUR_CHAR).to_u16()), FOREGROUND).0 else {
|
||||
panic!("colour art")
|
||||
};
|
||||
assert!(children(&root).is_empty(), "{:?}", children(&root).iter().map(|c| c.kind_label()).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
/// A COLRv1 color line through `stops` (offset, palette index) that extends by `extend`.
|
||||
fn color_line(extend: write_fonts::tables::colr::Extend, stops: &[(f32, u16)]) -> write_fonts::tables::colr::ColorLine {
|
||||
use write_fonts::tables::colr::{ColorLine, ColorStop};
|
||||
|
||||
Reference in New Issue
Block a user