From bd5f2f95e8687025af0518671af26ddda1aab88b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 2 Jan 2024 11:36:53 -0700 Subject: [PATCH] Add capability to synthesize italic --- Cargo.toml | 1 + examples/rich-text/src/main.rs | 8 ++++++-- src/attrs.rs | 15 ++++++++++++++- src/glyph_cache.rs | 14 ++++++++++++++ src/layout.rs | 5 ++++- src/shape.rs | 7 ++++++- src/swash.rs | 12 ++++++++++-- 7 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2a7d870..7ca595c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index bd16b20..8de45c0 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -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), diff --git a/src/attrs.rs b/src/attrs.rs index e163124..8ba4928 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -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, } } } diff --git a/src/glyph_cache.rs b/src/glyph_cache.rs index ce93b38..9e6d508 100644 --- a/src/glyph_cache.rs +++ b/src/glyph_cache.rs @@ -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, diff --git a/src/layout.rs b/src/layout.rs index 3825226..bcc20ef 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -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, /// 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 } diff --git a/src/shape.rs b/src/shape.rs index e480a66..5af4bb3 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -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, 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, } } } diff --git a/src/swash.rs b/src/swash.rs index 24fcd58..7c35ce9 100644 --- a/src/swash.rs +++ b/src/swash.rs @@ -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) }