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" rust-version = "1.65"
[dependencies] [dependencies]
bitflags = "2.4.1"
cosmic_undo_2 = { version = "0.2.0", optional = true } cosmic_undo_2 = { version = "0.2.0", optional = true }
fontdb = { version = "0.16.0", default-features = false } fontdb = { version = "0.16.0", default-features = false }
hashbrown = { version = "0.14.1", optional = true, 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 // SPDX-License-Identifier: MIT OR Apache-2.0
use cosmic_text::{ use cosmic_text::{
Action, Attrs, Buffer, Color, Edit, Editor, Family, FontSystem, Metrics, Motion, Shaping, Action, Attrs, Buffer, CacheKeyFlags, Color, Edit, Editor, Family, FontSystem, Metrics, Motion,
Style, SwashCache, Weight, Shaping, Style, SwashCache, Weight,
}; };
use orbclient::{EventOption, Renderer, Window, WindowFlag}; use orbclient::{EventOption, Renderer, Window, WindowFlag};
use std::{ use std::{
@ -63,6 +63,10 @@ fn main() {
("Sans-Serif Normal ", attrs), ("Sans-Serif Normal ", attrs),
("Sans-Serif Bold ", attrs.weight(Weight::BOLD)), ("Sans-Serif Bold ", attrs.weight(Weight::BOLD)),
("Sans-Serif Italic ", attrs.style(Style::Italic)), ("Sans-Serif Italic ", attrs.style(Style::Italic)),
(
"Sans-Serif Fake Italic ",
attrs.cache_key_flags(CacheKeyFlags::FAKE_ITALIC),
),
( (
"Sans-Serif Bold Italic\n", "Sans-Serif Bold Italic\n",
attrs.weight(Weight::BOLD).style(Style::Italic), attrs.weight(Weight::BOLD).style(Style::Italic),

View file

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

View file

@ -1,5 +1,15 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // 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 /// Key for building a glyph cache
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CacheKey { pub struct CacheKey {
@ -13,6 +23,8 @@ pub struct CacheKey {
pub x_bin: SubpixelBin, pub x_bin: SubpixelBin,
/// Binning of fractional Y offset /// Binning of fractional Y offset
pub y_bin: SubpixelBin, pub y_bin: SubpixelBin,
/// [`CacheKeyFlags`]
pub flags: CacheKeyFlags,
} }
impl CacheKey { impl CacheKey {
@ -21,6 +33,7 @@ impl CacheKey {
glyph_id: u16, glyph_id: u16,
font_size: f32, font_size: f32,
pos: (f32, f32), pos: (f32, f32),
flags: CacheKeyFlags,
) -> (Self, i32, i32) { ) -> (Self, i32, i32) {
let (x, x_bin) = SubpixelBin::new(pos.0); let (x, x_bin) = SubpixelBin::new(pos.0);
let (y, y_bin) = SubpixelBin::new(pos.1); let (y, y_bin) = SubpixelBin::new(pos.1);
@ -31,6 +44,7 @@ impl CacheKey {
font_size_bits: font_size.to_bits(), font_size_bits: font_size.to_bits(),
x_bin, x_bin,
y_bin, y_bin,
flags,
}, },
x, x,
y, y,

View file

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

View file

@ -13,7 +13,8 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::fallback::FontFallbackIter; use crate::fallback::FontFallbackIter;
use crate::{ 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. /// The shaping strategy of some text.
@ -148,6 +149,7 @@ fn shape_fallback(
//TODO: color should not be related to shaping //TODO: color should not be related to shaping
color_opt: attrs.color_opt, color_opt: attrs.color_opt,
metadata: attrs.metadata, metadata: attrs.metadata,
cache_key_flags: attrs.cache_key_flags,
}); });
} }
@ -373,6 +375,7 @@ fn shape_skip(
glyph_id, glyph_id,
color_opt: attrs.color_opt, color_opt: attrs.color_opt,
metadata: attrs.metadata, metadata: attrs.metadata,
cache_key_flags: attrs.cache_key_flags,
} }
}), }),
); );
@ -393,6 +396,7 @@ pub struct ShapeGlyph {
pub glyph_id: u16, pub glyph_id: u16,
pub color_opt: Option<Color>, pub color_opt: Option<Color>,
pub metadata: usize, pub metadata: usize,
pub cache_key_flags: CacheKeyFlags,
} }
impl ShapeGlyph { impl ShapeGlyph {
@ -418,6 +422,7 @@ impl ShapeGlyph {
y_offset: self.y_offset, y_offset: self.y_offset,
color_opt: self.color_opt, color_opt: self.color_opt,
metadata: self.metadata, 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::scale::{Render, Source, StrikeWith};
use swash::zeno::{Format, Vector}; 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::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( fn swash_image(
font_system: &mut FontSystem, font_system: &mut FontSystem,
@ -49,6 +49,14 @@ fn swash_image(
.format(Format::Alpha) .format(Format::Alpha)
// Apply the fractional offset // Apply the fractional offset
.offset(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 the image
.render(&mut scaler, cache_key.glyph_id) .render(&mut scaler, cache_key.glyph_id)
} }