Add capability to synthesize italic

This commit is contained in:
Jeremy Soller 2024-01-02 11:36:53 -07:00
parent 46d60a3723
commit bd5f2f95e8
7 changed files with 55 additions and 7 deletions

View file

@ -10,6 +10,7 @@ repository = "https://github.com/pop-os/cosmic-text"
rust-version = "1.65"
[dependencies]
bitflags = "2.4.1"
cosmic_undo_2 = { version = "0.2.0", optional = true }
fontdb = { version = "0.16.0", default-features = false }
hashbrown = { version = "0.14.1", optional = true, default-features = false }

View file

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use cosmic_text::{
Action, Attrs, Buffer, Color, Edit, Editor, Family, FontSystem, Metrics, Motion, Shaping,
Style, SwashCache, Weight,
Action, Attrs, Buffer, CacheKeyFlags, Color, Edit, Editor, Family, FontSystem, Metrics, Motion,
Shaping, Style, SwashCache, Weight,
};
use orbclient::{EventOption, Renderer, Window, WindowFlag};
use std::{
@ -63,6 +63,10 @@ fn main() {
("Sans-Serif Normal ", attrs),
("Sans-Serif Bold ", attrs.weight(Weight::BOLD)),
("Sans-Serif Italic ", attrs.style(Style::Italic)),
(
"Sans-Serif Fake Italic ",
attrs.cache_key_flags(CacheKeyFlags::FAKE_ITALIC),
),
(
"Sans-Serif Bold Italic\n",
attrs.weight(Weight::BOLD).style(Style::Italic),

View file

@ -6,9 +6,11 @@ use alloc::{
vec::Vec,
};
use core::ops::Range;
use rangemap::RangeMap;
use crate::CacheKeyFlags;
pub use fontdb::{Family, Stretch, Style, Weight};
use rangemap::RangeMap;
/// Text color
#[derive(Clone, Copy, Debug, PartialOrd, Ord, Eq, Hash, PartialEq)]
@ -109,6 +111,7 @@ pub struct Attrs<'a> {
pub style: Style,
pub weight: Weight,
pub metadata: usize,
pub cache_key_flags: CacheKeyFlags,
}
impl<'a> Attrs<'a> {
@ -123,6 +126,7 @@ impl<'a> Attrs<'a> {
style: Style::Normal,
weight: Weight::NORMAL,
metadata: 0,
cache_key_flags: CacheKeyFlags::empty(),
}
}
@ -162,6 +166,12 @@ impl<'a> Attrs<'a> {
self
}
/// Set [`CacheKeyFlags`]
pub fn cache_key_flags(mut self, cache_key_flags: CacheKeyFlags) -> Self {
self.cache_key_flags = cache_key_flags;
self
}
/// Check if font matches
pub fn matches(&self, face: &fontdb::FaceInfo) -> bool {
//TODO: smarter way of including emoji
@ -190,6 +200,7 @@ pub struct AttrsOwned {
pub style: Style,
pub weight: Weight,
pub metadata: usize,
pub cache_key_flags: CacheKeyFlags,
}
impl AttrsOwned {
@ -201,6 +212,7 @@ impl AttrsOwned {
style: attrs.style,
weight: attrs.weight,
metadata: attrs.metadata,
cache_key_flags: attrs.cache_key_flags,
}
}
@ -212,6 +224,7 @@ impl AttrsOwned {
style: self.style,
weight: self.weight,
metadata: self.metadata,
cache_key_flags: self.cache_key_flags,
}
}
}

View file

@ -1,5 +1,15 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
bitflags::bitflags! {
/// Flags that change rendering
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct CacheKeyFlags: u32 {
/// Skew by 14 degrees to synthesize italic
const FAKE_ITALIC = 1;
}
}
/// Key for building a glyph cache
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CacheKey {
@ -13,6 +23,8 @@ pub struct CacheKey {
pub x_bin: SubpixelBin,
/// Binning of fractional Y offset
pub y_bin: SubpixelBin,
/// [`CacheKeyFlags`]
pub flags: CacheKeyFlags,
}
impl CacheKey {
@ -21,6 +33,7 @@ impl CacheKey {
glyph_id: u16,
font_size: f32,
pos: (f32, f32),
flags: CacheKeyFlags,
) -> (Self, i32, i32) {
let (x, x_bin) = SubpixelBin::new(pos.0);
let (y, y_bin) = SubpixelBin::new(pos.1);
@ -31,6 +44,7 @@ impl CacheKey {
font_size_bits: font_size.to_bits(),
x_bin,
y_bin,
flags,
},
x,
y,

View file

@ -5,7 +5,7 @@ use core::fmt::Display;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::{CacheKey, Color};
use crate::{CacheKey, CacheKeyFlags, Color};
/// A laid out glyph
#[derive(Clone, Debug)]
@ -50,6 +50,8 @@ pub struct LayoutGlyph {
pub color_opt: Option<Color>,
/// Metadata from `Attrs`
pub metadata: usize,
/// [`CacheKeyFlags`]
pub cache_key_flags: CacheKeyFlags,
}
#[derive(Clone, Debug)]
@ -75,6 +77,7 @@ impl LayoutGlyph {
(self.x + x_offset) * scale + offset.0,
libm::truncf((self.y - y_offset) * scale + offset.1), // Hinting in Y axis
),
self.cache_key_flags,
);
PhysicalGlyph { cache_key, x, y }

View file

@ -13,7 +13,8 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::fallback::FontFallbackIter;
use crate::{
Align, AttrsList, Color, Font, FontSystem, LayoutGlyph, LayoutLine, ShapePlanCache, Wrap,
Align, AttrsList, CacheKeyFlags, Color, Font, FontSystem, LayoutGlyph, LayoutLine,
ShapePlanCache, Wrap,
};
/// The shaping strategy of some text.
@ -148,6 +149,7 @@ fn shape_fallback(
//TODO: color should not be related to shaping
color_opt: attrs.color_opt,
metadata: attrs.metadata,
cache_key_flags: attrs.cache_key_flags,
});
}
@ -373,6 +375,7 @@ fn shape_skip(
glyph_id,
color_opt: attrs.color_opt,
metadata: attrs.metadata,
cache_key_flags: attrs.cache_key_flags,
}
}),
);
@ -393,6 +396,7 @@ pub struct ShapeGlyph {
pub glyph_id: u16,
pub color_opt: Option<Color>,
pub metadata: usize,
pub cache_key_flags: CacheKeyFlags,
}
impl ShapeGlyph {
@ -418,6 +422,7 @@ impl ShapeGlyph {
y_offset: self.y_offset,
color_opt: self.color_opt,
metadata: self.metadata,
cache_key_flags: self.cache_key_flags,
}
}
}

View file

@ -7,10 +7,10 @@ use swash::scale::{image::Content, ScaleContext};
use swash::scale::{Render, Source, StrikeWith};
use swash::zeno::{Format, Vector};
use crate::{CacheKey, Color, FontSystem, HashMap};
use crate::{CacheKey, CacheKeyFlags, Color, FontSystem, HashMap};
pub use swash::scale::image::{Content as SwashContent, Image as SwashImage};
pub use swash::zeno::{Command, Placement};
pub use swash::zeno::{Angle, Command, Placement, Transform};
fn swash_image(
font_system: &mut FontSystem,
@ -49,6 +49,14 @@ fn swash_image(
.format(Format::Alpha)
// Apply the fractional offset
.offset(offset)
.transform(if cache_key.flags.contains(CacheKeyFlags::FAKE_ITALIC) {
Some(Transform::skew(
Angle::from_degrees(14.0),
Angle::from_degrees(0.0),
))
} else {
None
})
// Render the image
.render(&mut scaler, cache_key.glyph_id)
}